package server

import (
	"context"
	"gitee.com/crack007/goose/gsutil"
	"strings"
	"time"
)

var clientId = gsutil.NewSnowflake()

type ClientBuilder struct {
	host               string
	port               uint16
	network            string
	onMessage          func(client *Client, data []byte)
	readBuffer         uint
	readMsgQueueSize   uint
	writeMsgQueueSize  uint
	writeTimeout       time.Duration // 写入超时时间。
	writeIdleTimeout   time.Duration // 写入空闲时间。
	readIdleTimeout    time.Duration // 读空闲超时时间。
	idleTimeout        time.Duration // 空闲超时时间。
	reconnectInterval  uint
	onReadIdleTimeout  func(client *Client)
	onWriteIdleTimeout func(client *Client)
	onIdleTimeout      func(client *Client)
	onConnect          func(client *Client)
	onError            func(client *Client, err error)
	onClose            func(client *Client)
	asyncSend          bool
}

func (x *ClientBuilder) SetAsyncSend(asyncSend bool) {
	x.asyncSend = asyncSend
}

func (x *ClientBuilder) SetReconnectInterval(reconnectInterval uint) {
	x.reconnectInterval = reconnectInterval
}

func (x *ClientBuilder) OnConnect(onConnect func(client *Client)) {
	x.onConnect = onConnect
}

func (x *ClientBuilder) OnReadIdleTimeout(onReadIdleTimeout func(client *Client)) {
	x.onReadIdleTimeout = onReadIdleTimeout
}

func (x *ClientBuilder) OnWriteIdleTimeout(onWriteIdleTimeout func(client *Client)) {
	x.onWriteIdleTimeout = onWriteIdleTimeout
}

func (x *ClientBuilder) OnIdleTimeout(onIdleTimeout func(client *Client)) {
	x.onIdleTimeout = onIdleTimeout
}

func (x *ClientBuilder) OnClose(onClose func(client *Client)) {
	x.onClose = onClose
}

func (x *ClientBuilder) SetWriteIdleTimeout(writeIdleTimeout time.Duration) {
	x.writeIdleTimeout = writeIdleTimeout
}

func (x *ClientBuilder) SetReadIdleTimeout(readIdleTimeout time.Duration) {
	x.readIdleTimeout = readIdleTimeout
}

func (x *ClientBuilder) SetIdleTimeout(idleTimeout time.Duration) {
	x.idleTimeout = idleTimeout
}

func (x *ClientBuilder) SetNetwork(network string) *ClientBuilder {
	x.network = network
	return x
}

func (x *ClientBuilder) SetWriteTimeout(writeTimeout time.Duration) *ClientBuilder {
	x.writeTimeout = writeTimeout
	return x
}

func (x *ClientBuilder) OnMessage(OnMessage func(client *Client, data []byte)) *ClientBuilder {
	x.onMessage = OnMessage
	return x
}

func (x *ClientBuilder) SetReadBuffer(readBuffer uint) *ClientBuilder {
	x.readBuffer = readBuffer
	return x
}

func (x *ClientBuilder) SetReadMsgQueueSize(readMsgQueueSize uint) *ClientBuilder {
	x.readMsgQueueSize = readMsgQueueSize
	return x
}

func (x *ClientBuilder) SetWriteMsgQueueSize(writeMsgQueueSize uint) *ClientBuilder {
	x.writeMsgQueueSize = writeMsgQueueSize
	return x
}

func (x *ClientBuilder) OnError(onError func(client *Client, err error)) {
	x.onError = onError
}

func (x *ClientBuilder) Build() *Client {
	ctx, cancelFunc := context.WithCancel(context.Background())
	if x.readMsgQueueSize == 0 {
		x.readMsgQueueSize = 1024
	}

	if x.writeMsgQueueSize == 0 {
		x.writeMsgQueueSize = 1024
	}

	if x.readBuffer == 0 {
		x.readBuffer = 0xffff
	}

	if x.network == "" {
		x.network = "tcp"
	}

	if x.onError == nil {
		x.onError = func(client *Client, err error) {
		}
	}

	if x.onClose == nil {
		x.onClose = func(client *Client) {
		}
	}

	client := &Client{
		Host:                    x.host,
		Port:                    x.port,
		network:                 x.network,
		readBuffer:              x.readBuffer,
		readMsgQueueSize:        x.readMsgQueueSize,
		writeMsgQueueSize:       x.writeMsgQueueSize,
		ctx:                     ctx,
		cancel:                  cancelFunc,
		onMessage:               x.onMessage,
		writeMsgQueue:           make(chan []byte, x.writeMsgQueueSize),
		readMsgQueue:            make(chan []byte, x.readMsgQueueSize),
		idleTimeout:             x.idleTimeout,
		writeIdleTimeout:        x.writeIdleTimeout,
		readIdleTimeout:         x.readIdleTimeout,
		writeIdleTimeoutHandler: x.onWriteIdleTimeout,
		readIdleTimeoutHandler:  x.onReadIdleTimeout,
		idleTimeoutHandler:      x.onIdleTimeout,
		connectHandler:          x.onConnect,
		errorHandler:            x.onError,
		reconnectInterval:       x.reconnectInterval,
		isUnix:                  strings.ToLower(x.network) == "unix",
		reConnect:               true,
		id:                      clientId.NextId(),
		closeHandler:            x.onClose,
		asyncSend:               x.asyncSend,
	}
	return client
}

func NewClientBuilder(host string, port uint16) *ClientBuilder {
	return &ClientBuilder{
		host:      host,
		port:      port,
		asyncSend: true,
	}
}
